package org.yaukie.auth.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.filter.CorsFilter;
import org.yaukie.auth.filter.JwtAuthenticationFilter;
import org.yaukie.auth.handler.LoginOutSuccessHandler;
import org.yaukie.auth.handler.UnAuthorizationHandler;
import org.yaukie.base.text.Convert;
import org.yaukie.base.util.StringTools;

import javax.annotation.PostConstruct;


@ConditionalOnProperty(prefix = "yaukie.auth", name = {"enabled"}, havingValue = "true")
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig
        extends WebSecurityConfigurerAdapter {
    private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);


    @Value("${yaukie.auth.enabled}")
    private String enabled;

    @Value("${yaukie.auth.encoder.type:default}")
    private String ifMd5;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @Autowired
    private LoginOutSuccessHandler loginOutSuccessHandler;

    @Autowired
    private UnAuthorizationHandler unAuthorizationHandler;

    @Autowired
    private CorsFilter corsFilter;


    @PostConstruct
    public void init() {
        if (log.isInfoEnabled()) {
            if (Convert.toBool(this.enabled).booleanValue()) {
                log.info("已开启登录认证模块...系统将提供认证机制...");
                log.info("未开启登录认证模块...");
            }
        }
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, new String[]{
                        "/config/**", "/css/**", "/fonts/**", "/img/**", "/js/**", "/*.html", "/**.html", "/**.css", "/**.js", "/op/xlog/downLog/**"
                }).permitAll()

                .antMatchers(new String[]{"/sso/login", "/capcha/verifyImg"}).anonymous()

                .antMatchers(new String[]{"/provider/**"}).anonymous()
                .antMatchers(new String[]{"/api/xjob/getJobImage"}).anonymous()
                .antMatchers(new String[]{"/api/xtrans/getTransImage"}).anonymous()
                .antMatchers(new String[]{"/op/xlog/downLog/**"}).anonymous()
                .antMatchers(new String[]{"/help/**"}).anonymous()
                .antMatchers(new String[]{"/profile/**"}).anonymous()
                .antMatchers(new String[]{"/swagger-*.html"}).anonymous()
                .antMatchers(new String[]{"/swagger-resources/**"}).anonymous()
                .antMatchers(new String[]{"/webjars/**"}).anonymous()
                .antMatchers(new String[]{"/api-docs"}).anonymous()
                .antMatchers(new String[]{"/druid/**"}).anonymous()

                .anyRequest().authenticated()
                .and()
                .exceptionHandling().authenticationEntryPoint(this.unAuthorizationHandler).and()
                .headers().frameOptions().disable();

        http.logout().logoutUrl("/logout").logoutSuccessHandler(this.loginOutSuccessHandler);

        http.addFilterBefore(this.jwtAuthenticationFilter, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class);

        http.addFilterBefore(this.corsFilter, JwtAuthenticationFilter.class);
        http.addFilterBefore(this.corsFilter, org.springframework.security.web.authentication.logout.LogoutFilter.class);
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        if (StringTools.equals("md5", this.ifMd5)) {
            Md5PasswordEncoder md5PasswordEncoder = (Md5PasswordEncoder) passwordMd5Encoder();

            md5PasswordEncoder.setSalt("yuenbinisagreatman!");
            auth.userDetailsService(this.userDetailsService).passwordEncoder(md5PasswordEncoder);
            log.info("系统使用MD5加密方式......");
        } else {
            auth.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
            log.info("系统使用强散列加密方式......");
        }
    }


    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @ConditionalOnProperty(prefix = "yaukie.auth.encoder", value = {"type"}, havingValue = "md5")
    @Bean
    public PasswordEncoder passwordMd5Encoder() {
        return Md5PasswordEncoder.getInstance();
    }
}
